import * as CryptoJS from 'crypto-js';

type encryptOptions = {
    word: string | object,
    key?: string,
    success: (reslut: string) => void,
    fail: (error: { code: number, msg: string }) => void
}

type decryptOptions = {
    word: string,
    key?: string,
    type?: 'string' | 'object',
    success: (reslut: string | object) => void,
    fail: (error: { code: number, msg: string }) => void
}

type MD5Options = {
    word: string,
    success: (reslut: CryptoJS.lib.WordArray) => void,
    fail: (error: { code: number, msg: string }) => void
}

class Crypto {
    public key: string;
    constructor(key: string) {
        this.key = key; //十六位十六进制数作为密钥
    }

    /**
     * @name 对称加密
     * @param {object | String} option 配置对象 | 加密的文本
     * @param {string | object} [option.word] 加密的文本 string | object 
     * @param {string} [option.key] 秘钥 非必填
     * @param {Function} [option.success] 返回加密后的文本
     * @param {Function} [option.fail] 失败后返回
     * @returns {string} 加密后的文本
    */
    ACEencrypt(option: encryptOptions | string | Record<string, any>,): string | undefined {
        let options: encryptOptions = {
            word: "",
            key: this.key,
            success: () => { },
            fail: () => { }
        }
        if (typeof option == 'string') {
            options.word = option;
            option = {};
        }
        Object.assign(options, option);
        if (!options.word) {
            options.fail({ code: -1, msg: "需要加密的文字必填" })
            throw Error("需要加密的文字必填")
        }
        let isString = true;
        if (typeof options.word !== 'string') isString = false;
        let isObject = true;
        if (typeof options.word !== 'object') isObject = false;
        if (!isString && !isObject) {
            options.fail({ code: -1, msg: "加密的文字必须是字符串或者对象" });
            throw Error("加密的文字必须是字符串或者对象");
        }
        if (isObject) options.word = JSON.stringify(options.word);
        const myKey = options.key ? options.key : 'abcdefgabcdefg12';
        const utf8_key = CryptoJS.enc.Utf8.parse(myKey);
        const Text = CryptoJS.enc.Utf8.parse(options.word as string);
        let encrypText = CryptoJS.AES.encrypt(Text, utf8_key, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        })
        options.success(encrypText.toString())
        return encrypText.toString();
    }

    /**
     * @name 对称解密
     * @param {object | String} option 配置对象 | 解密的文本
     * @param {string | object} [option.word] 加密的文本 string | object 
     * @param {string} [option.key] 秘钥 非必填
     * @param {string | object} [option.type] 返回类型 string | object 
     * @param {Function} [option.success] 返回加密后的文本
     * @param {Function} [option.fail] 失败后返回
     * @returns {string | object} 解密后的文本
    */
    ACEdecrypt(option: decryptOptions | string | Record<string, any>) {
        let options: decryptOptions = {
            word: "",
            key: this.key,
            type: "string",
            success: () => { },
            fail: () => { }
        }
        if (typeof option == 'string') {
            options.word = option;
            option = {};
        }
        Object.assign(options, option);
        if (!options.word) {
            options.fail({ code: -1, msg: "需要加密的文字必填" })
            throw Error("需要加密的文字必填")
        }
        if (typeof options.word !== 'string') {
            options.fail({ code: -1, msg: "解密的文本必须是字符串" });
            throw Error("解密的文本必须是字符串");
        }
        const myKey = options.key ? options.key : 'abcdefgabcdefg12';
        const utf8_key = CryptoJS.enc.Utf8.parse(myKey);
        let decryptText = CryptoJS.AES.decrypt(options.word, utf8_key, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        })
        let sendDecryptText = CryptoJS.enc.Utf8.stringify(decryptText).toString();
        if (options.type == 'object') {
            decryptText = JSON.parse(sendDecryptText)
        }
        options.success(sendDecryptText);
        return sendDecryptText;
    }

    /**
     * @name MD5加密
     * @param {object | String} option 配置对象 | 加密的文本
     * @param {string | object} option.word 加密的文本 string | object
     * @param {Function} [option.success] 返回加密后的文本
     * @param {Function} [option.fail] 失败后返回
     * @returns {string} 加密后的文本
    */
   MD5(option:MD5Options | string | Record<string, any>) {
        let options:MD5Options = {
            word: "",
            success: () => { },
            fail: () => { }
        }
        if (typeof option == 'string') {
            options.word = option;
            option = {};
        }
        Object.assign(options, option);
        if (!options.word) {
            options.fail({ code: -1, msg: "需要加密的文字必填" })
            throw Error("需要加密的文字必填")
        }
        let isString = true;
        if (typeof options.word !== 'string') isString = false;
        let isObject = true;
        if (typeof options.word !== 'object') isObject = false;
        if (!isString && !isObject) {
            options.fail({ code: -1, msg: "加密的文字必须是字符串或者对象" });
            throw Error("加密的文字必须是字符串或者对象");
        }
        if (isObject) options.word = JSON.stringify(options.word);
        const Text = CryptoJS.enc.Utf8.parse(options.word);
        let encrypText = CryptoJS.MD5(Text);
        options.success(encrypText);
        return encrypText.toString();
    }
}



export const moreCrypto = CryptoJS;


export default new Crypto("JXU5NkM2JXU1NkUyJXU4RkQwJXU4NDI1JXU2NTcwJXU1QjU3JXU1MzE2JXU1MjA2JXU2NzkwJXU1RTczJXU1M0Yw");